#ifndef _VFX_SHATTER_H_
#define _VFX_SHATTER_H_

/////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// VFXShatterFX
// ------------
//
// Takes an image, breaks it up into triangle shards, and shatters it
//
// TODO: Update usage, changes have been made
// Usage:
// ------
// 1) Call Setup to initialize the object
// 2) Call SetPos to setup the screen position of the object
// 3) Call Shatter to shatter the object, passing in parameters to control the behavior of the individual shards
//    - SpeedMinMax: Minimum and Maximum speed, compressed in a Vec2 (i.e. x = min, y = max)
//    - AccelerationMin: Minimum acceleration
//    - AccelerationMax: Maximum acceleration
//    - LifeMinMax: Minimum and maximum life, compressed in a Vec2
//    - RotationMinMax: Minimum and maximum rotation speed (in deg/sec), compressed in a Vec2
//
// Notes:
// ------
// - The object can be re-used by calling Setup to reinitialize itself
//

#include "ui/ui_sprite.h"
#include "math/counter.h"

namespace vfx
{

/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Elements group -- override VFXShatterElement to support something other than sprites (e.g. ImageCaches, or Bipeds via ImageCaches)

class VFXShatterElement
{
public:
	VFXShatterElement(const std::string& Name) : m_Name(Name) {}
	virtual ~VFXShatterElement() {}

	virtual void		Tick(float dt) = 0;
	virtual void		Render(Graphics::Vertex2D* VertA, unsigned int VertC) = 0;
	virtual math::Vec2	GetSize() = 0;

protected:
	std::string			m_Name;
};

class VFXShatterSprite : public VFXShatterElement
{
public:
	VFXShatterSprite(const std::string& Name)	: VFXShatterElement(Name)
												{ m_Sprite.Create(Name); }
	virtual ~VFXShatterSprite()					{}

	virtual void		Tick(float dt)			{ m_Sprite.Tick(dt); }
	virtual void		Render(Graphics::Vertex2D* VertA, unsigned int VertC);
	virtual math::Vec2	GetSize()				{ return m_Sprite.m_Size; }

private:
	ui::UISprite		m_Sprite;
};

/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Shatter block -- select appropriate class based on desired effect

class VFXShatterFXBase
{
public:
	struct SHARD_DATA
	{
		static const int	MAX_POINTS = 4;

		math::Vec2		Pos;
		math::Vec2		Size;
		math::Vec2		PointA[MAX_POINTS];
		math::Vec2		UVA[MAX_POINTS];
		int				PointC;
		math::Vec2		Velocity;
		float			Rotation;
		float			RotSpeed;
		math::Counter	Life;
		int				CustomID;
		bool			IsAlive;
		void*			pvCustomData;
	};

	VFXShatterFXBase(bool EnableFade = true);
	virtual ~VFXShatterFXBase();

	bool				Setup(VFXShatterElement* pElement, unsigned int SegmentW, unsigned int SetmentH);
	bool				Setup(const std::string& Sprite, unsigned int SegmentW, unsigned int SegmentH);

	void				Shatter(const math::Vec2& SpeedMinMax,
								const math::Vec2& LifeMinMax,
								const math::Vec2& RotationMinMax,
								const math::Vec2& CenterOffset = math::Vec2(0.0f, 0.0f));

	void				Tick(float dt);
	void				Render(const math::Vec2& Offset, float Scale = 1.0f);

	void				SetPos(const math::Vec2& Pos)	{ m_Pos = Pos; }
	const math::Vec2&	GetPos()						{ return m_Pos; }
	void				SetAcceleration(const math::Vec2& Accel)	{ m_Acceleration = Accel; }
	const math::Vec2&	GetAcceleration()				{ return m_Acceleration; }
	math::Vec2			GetSize()						{ return m_pElement ? m_pElement->GetSize() : math::Vec2(); }
	void				SetColor(COLOR c)				{ m_Color = c; }
	COLOR				GetColor() const				{ return m_Color; }
	void				SetEnableFade(bool b)			{ m_EnableFade = b; }
	bool				GetEnableFade() const			{ return m_EnableFade; }
	void				SetFadeDelay(float f);
	float				GetFadeDelay() const			{ return m_FadeDelay; }

	bool				IsInitialized() const			{ return m_IsInit; }
	bool				HasShattered() const			{ return m_IsShattered; }
	bool				IsActive() const				{ return m_IsShattered && (m_AliveC > 0); }

	SHARD_DATA*			GetShard(int idx)				{ return &m_ShardA[idx]; }
	unsigned int		GetShardCount() const			{ return m_ShardC; }

	// callbacks
	typedef void		(*ShatterStartCB)(SHARD_DATA* pShard, int CurrentIndex, VFXShatterFXBase* pShatterFX, void* pvData);
	typedef void		(*ShatterUpdateCB)(SHARD_DATA* pShard, float dt, VFXShatterFXBase* pShatterFX, void* pvData);

	void				SetupCustomShatter(ShatterStartCB pStartCB, ShatterUpdateCB pUpdateCB, void* pvStartData = NULL, void* pvUpdateData = NULL)
	{
						m_pShatterStartCB = pStartCB;
						m_pShatterUpdateCB = pUpdateCB;
						m_pvShatterStartData = pvStartData;
						m_pvShatterUpdateData = pvUpdateData;
	}

protected:
	inline COLOR		CalcShardColor(SHARD_DATA* pShard);

	virtual int			TrianglesPerShard() const = 0;
	virtual bool		CreateShard(SHARD_DATA** ppShardA) = 0;
	virtual void		UpdateShard(SHARD_DATA* pShard, float dt);
	virtual void		RenderShard(SHARD_DATA* pShard, const math::Vec2& Offset, float Scale, COLOR c, Graphics::Vertex2D* VertA, unsigned int& Idx) = 0;

	VFXShatterElement*	m_pElement;
	SHARD_DATA*			m_ShardA;
	unsigned int		m_ShardC;
	unsigned int		m_Width;
	unsigned int		m_Height;

private:
	math::Vec2			m_Pos;
	math::Vec2			m_Acceleration;
	COLOR				m_Color;
	int					m_AliveC;
	float				m_FadeDelay, m_InvFadeDelay;

	bool				m_EnableFade;
	bool				m_IsInit;
	bool				m_IsShattered;

	ShatterStartCB		m_pShatterStartCB;
	ShatterUpdateCB		m_pShatterUpdateCB;
	void*				m_pvShatterStartData;
	void*				m_pvShatterUpdateData;
};

class VFXShatterTriFX : public VFXShatterFXBase
{
public:
	VFXShatterTriFX(bool EnableFade = true) : VFXShatterFXBase(EnableFade) {}
	virtual ~VFXShatterTriFX() {}

protected:
	virtual int			TrianglesPerShard() const { return 1; }
	virtual bool		CreateShard(SHARD_DATA** ppShardA);
	virtual void		RenderShard(SHARD_DATA* pShard, const math::Vec2& Offset, float Scale, COLOR c, Graphics::Vertex2D* VertA, unsigned int& Idx);

private:
	enum TRIANGLE_CORNER
	{
		TOPLEFT,
		BOTTOMRIGHT,
	};
};

class VFXShatterRectFX : public VFXShatterFXBase
{
public:
	VFXShatterRectFX(bool EnableFade = true) : VFXShatterFXBase(EnableFade) {}
	virtual ~VFXShatterRectFX() {}

protected:
	virtual int			TrianglesPerShard() const { return 2; }
	virtual bool		CreateShard(SHARD_DATA** ppShardA);
	virtual void		RenderShard(SHARD_DATA* pShard, const math::Vec2& Offset, float Scale, COLOR c, Graphics::Vertex2D* VertA, unsigned int& Idx);
};

typedef VFXShatterTriFX VFXShatterFX; // for legacy compatibility purposes

}; //namespace vfx

#endif //_VFX_SHATTER_H_
